<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="egbm4" id="egbm4"><span data-lake-id="uc5ddfa28" id="uc5ddfa28">典型回答</span></h1>
  <p data-lake-id="u4f129aed" id="u4f129aed"><br></p>
  <p data-lake-id="ube6270a7" id="ube6270a7"><span data-lake-id="u30c1979b" id="u30c1979b">Seata是一个阿里开源的分布式事务解决方案（Simple Extensible Autonomous Transaction Architecture），用于在分布式系统中实现分布式事务。它旨在简化分布式事务的开发和管理，帮助解决分布式系统中的数据一致性问题。</span></p>
  <p data-lake-id="ufdf5fd2a" id="ufdf5fd2a"><span data-lake-id="uaef8ce2a" id="uaef8ce2a">​</span><br></p>
  <p data-lake-id="ud5c50d72" id="ud5c50d72"><span data-lake-id="u3f85e75b" id="u3f85e75b" class="lake-fontsize-12">Seata目前支持4种模式，分别是：</span></p>
  <p data-lake-id="u7a5685ab" id="u7a5685ab"><span data-lake-id="u671b2cb4" id="u671b2cb4" class="lake-fontsize-12">​</span><br></p>
  <ul list="u83ce14d8">
   <li fid="u0938b997" data-lake-id="uaf6c34e4" id="uaf6c34e4"><span data-lake-id="u2968abed" id="u2968abed" class="lake-fontsize-12">AT模式</span></li>
   <li fid="u0938b997" data-lake-id="ud5bfc429" id="ud5bfc429"><span data-lake-id="uc699aef8" id="uc699aef8" class="lake-fontsize-12">TCC模式</span></li>
   <li fid="u0938b997" data-lake-id="uab448fd0" id="uab448fd0"><span data-lake-id="u4702f7ff" id="u4702f7ff" class="lake-fontsize-12">Saga模式</span></li>
   <li fid="u0938b997" data-lake-id="ua3c4f792" id="ua3c4f792"><span data-lake-id="ua2edc977" id="ua2edc977" class="lake-fontsize-12">XA模式</span></li>
  </ul>
  <p data-lake-id="ua92a6218" id="ua92a6218"><br></p>
  <p data-lake-id="ucf933db7" id="ucf933db7"><span data-lake-id="u829ddb9c" id="u829ddb9c" class="lake-fontsize-12">先来对比下各种模式，后面的章节分别展开介绍；</span></p>
  <table data-lake-id="MWorG" id="MWorG" margin="true" width-mode="contain" class="lake-table" style="width: 1250px">
   <colgroup>
    <col width="250">
    <col width="250">
    <col width="250">
    <col width="250">
    <col width="250">
   </colgroup>
   <tbody>
    <tr data-lake-id="u1d51f3c7" id="u1d51f3c7">
     <td data-lake-id="u7941797d" id="u7941797d"></td>
     <td data-lake-id="u207fadf7" id="u207fadf7">
      <p data-lake-id="u13fe0156" id="u13fe0156"><span data-lake-id="uaa2ba725" id="uaa2ba725">XA</span></p></td>
     <td data-lake-id="ueb80748c" id="ueb80748c">
      <p data-lake-id="u7e0a9da4" id="u7e0a9da4"><span data-lake-id="uc01df3dc" id="uc01df3dc">AT</span></p></td>
     <td data-lake-id="u4400857f" id="u4400857f">
      <p data-lake-id="ube33f398" id="ube33f398"><span data-lake-id="uddca235c" id="uddca235c">TCC</span></p></td>
     <td data-lake-id="u85ed09fa" id="u85ed09fa">
      <p data-lake-id="ub7d66558" id="ub7d66558"><span data-lake-id="u09035b22" id="u09035b22">Saga</span></p></td>
    </tr>
    <tr data-lake-id="u587c7081" id="u587c7081">
     <td data-lake-id="ub8e47d63" id="ub8e47d63">
      <p data-lake-id="u9d1e6ba7" id="u9d1e6ba7"><span data-lake-id="uaa3db3d5" id="uaa3db3d5">一致性</span></p></td>
     <td data-lake-id="u32f65a80" id="u32f65a80">
      <p data-lake-id="uccc6e842" id="uccc6e842"><span data-lake-id="uadf85963" id="uadf85963">强一致</span></p></td>
     <td data-lake-id="u048b0671" id="u048b0671">
      <p data-lake-id="ube20cf8f" id="ube20cf8f"><span data-lake-id="u8b47d5ce" id="u8b47d5ce">弱一致</span></p></td>
     <td data-lake-id="u012d1c8b" id="u012d1c8b">
      <p data-lake-id="ub8fa7563" id="ub8fa7563"><span data-lake-id="u027eb976" id="u027eb976">弱一致</span></p></td>
     <td data-lake-id="u833b2b14" id="u833b2b14">
      <p data-lake-id="u4a804935" id="u4a804935"><span data-lake-id="uc73ade12" id="uc73ade12">最终一致</span></p></td>
    </tr>
    <tr data-lake-id="u9546564d" id="u9546564d">
     <td data-lake-id="u552447bd" id="u552447bd">
      <p data-lake-id="uc7fce365" id="uc7fce365"><span data-lake-id="u8fe18323" id="u8fe18323">隔离性</span></p></td>
     <td data-lake-id="u7d59d92d" id="u7d59d92d">
      <p data-lake-id="ud00eddec" id="ud00eddec"><span data-lake-id="uba5480e7" id="uba5480e7">完全隔离</span></p></td>
     <td data-lake-id="u366477e2" id="u366477e2">
      <p data-lake-id="u9a00066c" id="u9a00066c"><span data-lake-id="u846072af" id="u846072af">基于全局锁隔离</span></p></td>
     <td data-lake-id="ub4cf1454" id="ub4cf1454">
      <p data-lake-id="u91df05b0" id="u91df05b0"><span data-lake-id="u51036786" id="u51036786">基于资源预留隔离</span></p></td>
     <td data-lake-id="u7ace9abe" id="u7ace9abe">
      <p data-lake-id="u26f91486" id="u26f91486"><span data-lake-id="u27137f6b" id="u27137f6b">无隔离</span></p></td>
    </tr>
    <tr data-lake-id="u76a98c56" id="u76a98c56">
     <td data-lake-id="u31e8217b" id="u31e8217b">
      <p data-lake-id="ubfebea93" id="ubfebea93"><span data-lake-id="ua404038c" id="ua404038c">代码侵入性</span></p></td>
     <td data-lake-id="uf71a528e" id="uf71a528e">
      <p data-lake-id="u674f6a76" id="u674f6a76"><span data-lake-id="uf3c3b39b" id="uf3c3b39b">无</span></p></td>
     <td data-lake-id="u13e9199a" id="u13e9199a">
      <p data-lake-id="ub449cfff" id="ub449cfff"><span data-lake-id="u58bcf438" id="u58bcf438">无</span></p></td>
     <td data-lake-id="u5e61ab41" id="u5e61ab41">
      <p data-lake-id="u1e7cf7c5" id="u1e7cf7c5"><span data-lake-id="ucd4f417b" id="ucd4f417b">有，要编写TCC三个接口</span></p></td>
     <td data-lake-id="u8aa33df0" id="u8aa33df0">
      <p data-lake-id="uac6003bf" id="uac6003bf"><span data-lake-id="ua35732cd" id="ua35732cd">有，要编写状态机及补偿代码</span></p></td>
    </tr>
    <tr data-lake-id="u7a65ff6d" id="u7a65ff6d">
     <td data-lake-id="u47d4404b" id="u47d4404b">
      <p data-lake-id="ub90911b4" id="ub90911b4"><span data-lake-id="ueb90df52" id="ueb90df52">性能</span></p></td>
     <td data-lake-id="u324c2128" id="u324c2128">
      <p data-lake-id="ue3af939f" id="ue3af939f"><span data-lake-id="uc9b680fd" id="uc9b680fd">差</span></p></td>
     <td data-lake-id="u6c9bbc55" id="u6c9bbc55">
      <p data-lake-id="u8727c7c5" id="u8727c7c5"><span data-lake-id="ubb5f2446" id="ubb5f2446">高</span></p></td>
     <td data-lake-id="u53777003" id="u53777003">
      <p data-lake-id="u6f360ac1" id="u6f360ac1"><span data-lake-id="u3679babc" id="u3679babc">非常高</span></p></td>
     <td data-lake-id="u807dcf60" id="u807dcf60">
      <p data-lake-id="ue94e7f05" id="ue94e7f05"><span data-lake-id="u8e7fb0e5" id="u8e7fb0e5">非常高</span></p></td>
    </tr>
    <tr data-lake-id="u46ca4d08" id="u46ca4d08">
     <td data-lake-id="uc01e8245" id="uc01e8245">
      <p data-lake-id="u0b4ae4b1" id="u0b4ae4b1"><span data-lake-id="u6f00f33e" id="u6f00f33e">适用场景</span></p></td>
     <td data-lake-id="u48a84332" id="u48a84332">
      <p data-lake-id="ud7d7901b" id="ud7d7901b"><span data-lake-id="u78bc47de" id="u78bc47de">对一致性、隔离性要求较高的场景</span></p></td>
     <td data-lake-id="u69fcc3a5" id="u69fcc3a5">
      <p data-lake-id="uf42d8d02" id="uf42d8d02"><span data-lake-id="u6a66a4ee" id="u6a66a4ee">基于关系型数据库的大多数分布式事务场景</span></p></td>
     <td data-lake-id="ue80eee82" id="ue80eee82">
      <p data-lake-id="u6da75546" id="u6da75546"><span data-lake-id="ue248833a" id="ue248833a">对性能要求高的场景，有非关系型数据库要参与的事务</span></p></td>
     <td data-lake-id="udc2cc220" id="udc2cc220">
      <p data-lake-id="ud75cd431" id="ud75cd431"><span data-lake-id="u46277264" id="u46277264">业务流程长且多。</span></p>
      <p data-lake-id="uc0bf288c" id="uc0bf288c"><span data-lake-id="u0f65ce85" id="u0f65ce85">参与者包含外部接口或者遗留接口，无法做TCC模式的</span></p></td>
    </tr>
    <tr data-lake-id="ue1b4ad6f" id="ue1b4ad6f">
     <td data-lake-id="u2f088fe1" id="u2f088fe1"></td>
     <td data-lake-id="uf0faa5ca" id="uf0faa5ca"></td>
     <td data-lake-id="u5070dfd3" id="u5070dfd3"></td>
     <td data-lake-id="u20ede606" id="u20ede606"></td>
     <td data-lake-id="ud77e8196" id="ud77e8196"></td>
    </tr>
   </tbody>
  </table>
  <p data-lake-id="u377dff2a" id="u377dff2a"><span data-lake-id="u3c4b9d07" id="u3c4b9d07">​</span><br></p>
  <h1 data-lake-id="DMQ2P" id="DMQ2P"><span data-lake-id="ub85e9e13" id="ub85e9e13">扩展知识</span></h1>
  <p data-lake-id="udd92eb06" id="udd92eb06"><br></p>
  <h2 data-lake-id="nqz11" id="nqz11"><span data-lake-id="u9c6b9449" id="u9c6b9449">Seata的实现原理</span></h2>
  <p data-lake-id="udf04c5bd" id="udf04c5bd"><br></p>
  <p data-lake-id="u4c4e72cb" id="u4c4e72cb"><span data-lake-id="ud09d016b" id="ud09d016b">因为Seata的开发者坚定地认为：一个分布式事务是有若干个本地事务组成的。所以他们给Seata体系的所有组件定义成了三种，分别是Transaction Coordinator、Transaction Manager和Resource Manager</span></p>
  <p data-lake-id="u55721238" id="u55721238"><br></p>
  <p data-lake-id="u7406ae3c" id="u7406ae3c"><strong><span data-lake-id="ud95049f5" id="ud95049f5">Transaction Coordinator(TC)</span></strong><span data-lake-id="u9bb67001" id="u9bb67001">: 这是一个独立的服务，是一个独立的 JVM 进程，里面不包含任何业务代码，它的主要职责：维护着整个事务的全局状态，负责通知 RM 执行回滚或提交；</span></p>
  <p data-lake-id="ub945a4f8" id="ub945a4f8"><span data-lake-id="uaf103260" id="uaf103260">​</span><br></p>
  <p data-lake-id="u7a60f3ca" id="u7a60f3ca"><strong><span data-lake-id="u8e0d1fec" id="u8e0d1fec">Transaction Manager(TM)</span></strong><span data-lake-id="ud3ee16fa" id="ud3ee16fa">: 在微服务架构中可对应为聚合服务，即将不同的微服务组合起来成一个完成的业务流程，TM 的职责是开启一个全局事务或者提交或回滚一个全局事务；</span></p>
  <p data-lake-id="u69a7f079" id="u69a7f079"><span data-lake-id="u007fd89e" id="u007fd89e">​</span><br></p>
  <p data-lake-id="ua26db804" id="ua26db804"><strong><span data-lake-id="u2ad3a316" id="u2ad3a316">Resource Manager(RM)</span></strong><span data-lake-id="uaa9021c9" id="uaa9021c9">：RM 在微服务框架中对应具体的某个微服务为事务的分支，RM 的职责是：执行每个事务分支的操作。</span></p>
  <p data-lake-id="u9fe279bd" id="u9fe279bd"><span data-lake-id="ud58c297e" id="ud58c297e">​</span><br></p>
  <p data-lake-id="uad7eddd5" id="uad7eddd5"><span data-lake-id="u5d351d36" id="u5d351d36">看上去好像很难理解？举个例子你就知道了：</span></p>
  <p data-lake-id="u2ead5fe3" id="u2ead5fe3"><span data-lake-id="u8b85cf17" id="u8b85cf17">​</span><br></p>
  <p data-lake-id="u43990d71" id="u43990d71"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691212535940-51d90d22-ad71-4274-a632-1ad27d661aa1.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_29%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u9fb97c62" id="u9fb97c62"><span data-lake-id="u26d8b6c1" id="u26d8b6c1">​</span><br></p>
  <p data-lake-id="u3da891d8" id="u3da891d8"><span data-lake-id="ue332cd87" id="ue332cd87">在一个下单事务中，我们有一个聚合的服务，姑且把他叫做TradeCenter吧，他负责接收并处理用户的下单请求，并且下单过程中需要调用订单服务（Order）、库存服务（Stock）及账户服务（Account）进行创建订单、扣减库存及增加积分。</span></p>
  <p data-lake-id="uc688cd9f" id="uc688cd9f"><span data-lake-id="u4b332d6f" id="u4b332d6f">​</span><br></p>
  <p data-lake-id="u5ea3b304" id="u5ea3b304"><span data-lake-id="uc741c28d" id="uc741c28d">所以TradeCenter担当的就是TM的角色，而Order、Stock及Account三个微服务就是RM的角色。在此之外，还需要一个独立的服务，维护分布式事务的全局状态，他就是TC。</span></p>
  <p data-lake-id="ua583aaa7" id="ua583aaa7"><br></p>
  <p data-lake-id="ub12bff80" id="ub12bff80"><span data-lake-id="ue110eb9f" id="ue110eb9f">因为TC维护着整个事务的全局状态，负责通知 RM 执行回滚或提交，所以他和TM、RM都是有交互的。并且TM和RM之间也有调用关系。多个RM之间可以是独立的。</span></p>
  <p data-lake-id="u8cc8696e" id="u8cc8696e"><span data-lake-id="ua321b7c4" id="ua321b7c4">​</span><br></p>
  <p data-lake-id="u69974b3d" id="u69974b3d"><span data-lake-id="ucca8f7e9" id="ucca8f7e9">上面这个场景中，要想保证分布式事务，就需要Order、Stock及Account三个服务对应的数据库表操作，要么都成功、要么都失败。不能有部分成功、部分失败的情况。</span></p>
  <p data-lake-id="ud66364b0" id="ud66364b0"><span data-lake-id="u72aa5f38" id="u72aa5f38">​</span><br></p>
  <p data-lake-id="u849676f0" id="u849676f0"><span data-lake-id="uc928ac1d" id="uc928ac1d">在用了Seata之后，一次分布式事务的大致流程如下（不同的模式略有不同，在介绍具体模式的时候分别展开）：</span></p>
  <p data-lake-id="u1248a077" id="u1248a077"><span data-lake-id="u59774ec9" id="u59774ec9">​</span><br></p>
  <p data-lake-id="u354e05cb" id="u354e05cb"><span data-lake-id="u7be1dc36" id="u7be1dc36">1、TM在接收到用户的下单请求后，会先调用TC创建一个全局事务，并且从TC获取到他生成的XID。</span></p>
  <p data-lake-id="u4d39a742" id="u4d39a742"><span data-lake-id="ub1b6bc45" id="ub1b6bc45">​</span><br></p>
  <p data-lake-id="uad16fbda" id="uad16fbda"><span data-lake-id="u38884ad2" id="u38884ad2">2、TM开始通过RPC/Restful调用各个RM，调用过程中需要把XID同时传递过去。</span></p>
  <p data-lake-id="ubc81da85" id="ubc81da85"><span data-lake-id="u46091650" id="u46091650">​</span><br></p>
  <p data-lake-id="u6db36f79" id="u6db36f79"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691213549843-0ba2065e-cdeb-4341-89f7-3e27c2af14af.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_29%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ucbdefa1e" id="ucbdefa1e"><span data-lake-id="ua74d9b8b" id="ua74d9b8b">​</span><br></p>
  <p data-lake-id="u46c230c4" id="u46c230c4"><span data-lake-id="u6f5606ff" id="u6f5606ff">3、</span><span data-lake-id="u7255055b" id="u7255055b">RM通过其接收到的XID,将其所管理的资源且被该调用锁使用到的资源注册为一个事务分支(Branch Transaction)</span></p>
  <p data-lake-id="u64ba09a4" id="u64ba09a4"><span data-lake-id="u568a3783" id="u568a3783">​</span><br></p>
  <p data-lake-id="uedc11e02" id="uedc11e02"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691213610596-d9084b3b-74a8-4f12-abcf-990717d93060.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_27%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u01cc5a3a" id="u01cc5a3a"><span data-lake-id="ud9e9450e" id="ud9e9450e">​</span><br></p>
  <p data-lake-id="u4a1cc2df" id="u4a1cc2df"><span data-lake-id="u0a30e996" id="u0a30e996">4、当该请求的调用链全部结束时，TM根据本次调用是否有失败的情况，如果所有调用都成功，则决议Commit，如果有超时或者失败，则决议Rollback。</span></p>
  <p data-lake-id="u1ff7ef46" id="u1ff7ef46"><span data-lake-id="uf89b1602" id="uf89b1602">​</span><br></p>
  <p data-lake-id="uf82fde1e" id="uf82fde1e"><span data-lake-id="u184c7954" id="u184c7954">5、TM将事务的决议结果通知TC，TC将协调所有RM进行事务的二阶段动作，该回滚回滚，该提交提交。</span></p>
  <p data-lake-id="u3a506bfd" id="u3a506bfd"><br></p>
  <p data-lake-id="u8e6b2302" id="u8e6b2302"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691213685250-ac8f2f0b-90d3-4f8f-a12f-892732f7c237.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_27%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"><span data-lake-id="u2f66b403" id="u2f66b403" class="lake-fontsize-12" style="color: rgb(36, 41, 46)"><br><br></span></p>
  <p data-lake-id="ub62f187a" id="ub62f187a"><span data-lake-id="ub6b45595" id="ub6b45595" class="lake-fontsize-12">这里要求所有的RM都能做到2阶段，第一阶段做事务的预处理，第二阶段做事务的提交或者回滚。具体怎么实现，是否需要自己改代码，这个不同的模式不太一样。</span></p>
  <p data-lake-id="ubf800dd7" id="ubf800dd7"><span data-lake-id="udc7837d9" id="udc7837d9" class="lake-fontsize-12">​</span><br></p>
  <p data-lake-id="u9ab96ee5" id="u9ab96ee5"><br></p>
 </body>
</html>